﻿Imports IICBusinessLogic.PeriodProcessing

Public Interface ICreditsAndExamsProcessor

    Property period() As Period

    ''' <summary>
    ''' Dictionary that contains only one record per student.  The studentId is the key of the Dictionary
    ''' </summary>
    Property dictStudentSatisfiedCertReqs() As Dictionary(Of String, IStudentSatisfiedCertReqs)

    ReadOnly Property classMembersProcessed() As List(Of ClassMember)

    Function getStudentSatisfiedCertReqs( _
                                ByVal student As Student, _
                                ByVal certType As CertificationType) As IStudentSatisfiedCertReqs

    Sub processCredits()

    Sub processExams()

End Interface

Public Class CreditsAndExamsProcessor
    Implements ICreditsAndExamsProcessor

    Private _ClassesToProcess As List(Of PeriodClass)

    Public Sub New(ByVal period As Period)
        Me.period = period

        If Me.period.DiplomaSuperTypeId = EnumDiplomaSuperTypes.DAS Then
            'for DAS periods, we also load for each student all PAS history

            Dim students As List(Of Student) = StudentDataUtils.findList("studentid in (select studentid from [vClassMember] where periodid={0})", Me.period.PeriodId)
            Me.addStudentToProcess(students.ToArray)

        End If

    End Sub

    Public Property period As Period Implements ICreditsAndExamsProcessor.period

    ''' <summary>
    ''' Dictionary that contains only one record per student.  The studentId is the key of the Dictionary
    ''' </summary>
    Public Property dictStudentSatisfiedCertReqs As Dictionary(Of String, IStudentSatisfiedCertReqs) Implements ICreditsAndExamsProcessor.dictStudentSatisfiedCertReqs

    Private _classMembersProcessed As List(Of ClassMember) = New List(Of ClassMember)

    Public ReadOnly Property classMembersProcessed As List(Of ClassMember) Implements ICreditsAndExamsProcessor.classMembersProcessed
        Get
            If _classMembersProcessed Is Nothing Then
                _classMembersProcessed = New List(Of ClassMember)
            End If
            Return _classMembersProcessed
        End Get
    End Property

    ''' <summary>
    ''' This is a public property to allow set of specific classes to process
    ''' </summary>
    Public Property ClassesToProcess() As List(Of PeriodClass)

        Get
            If _ClassesToProcess Is Nothing Then
                Me.period.Classes = Nothing 'reset classes to force reload
                _ClassesToProcess = Me.period.Classes.ToList
            End If
            Return _ClassesToProcess
        End Get
        Set(ByVal value As List(Of PeriodClass))
            _ClassesToProcess = value
        End Set
    End Property

    Public Sub processExams() Implements ICreditsAndExamsProcessor.processExams

        If Me.period.PeriodDate = DateSerial(2009, 6, 1) AndAlso Me.period.DiplomaSuperTypeId = EnumDiplomaSuperTypes.DAS Then
            Me.addStudentToProcess(2819, 862, 4214, 1309)
        End If

        Dim classes As List(Of PeriodClass) = Me.ClassesToProcess


        'loop thru each class in period
        For Each pc As PeriodClass In classes
            'Debug.WriteLine(pc.Lesson.LessonCode)
            'loop thru each member in class
            For Each cm As ClassMember In pc.Members

                'change: only process records that cm.PeriodProcessId is null
                If cm.PeriodProcessId Is Nothing Then

                    Me.classMembersProcessed.Add(cm)

                    If cm.Grade >= cm.PeriodClass.PassGrade Then

                        'loop thru the Certification Requirements that this class/lesson satisfies!
                        Dim lesson As Lesson = cm.PeriodClass.Lesson

                        'Debug.WriteLine("Passed lesson id::" & lesson.LessonId & "certREqs" & lesson.CertificationRequirements.Count)
                        Dim lessonReqs As IEnumerable(Of CertificationRequirement) = lesson.CertificationRequirementsOfDiplomaType(Me.period.DiplomaSuperType)
                        For Each dreq In lessonReqs
                            Dim ssr As IStudentSatisfiedCertReqs = Me.getStudentSatisfiedCertReqs(cm.Student, dreq.Certification)
                            Dim csr As CertificationSatisfiedRequirement = CertificationSatisfiedRequirementFactory.Create
                            csr.CertificationRequirementId = dreq.CertificationRequirementId
                            csr.ClassMemberId = cm.ClassMemberId

                            ssr.addSatifiedRequirement(csr)
                        Next
                    End If
                End If
            Next
        Next

    End Sub

    ''' <summary>
    ''' Manually add a student to the collections of students to check
    ''' This is used for DAS , where some people earned their certificates and diploma
    ''' from PAS classes. For example, member 2819 earned his DAS diploma on June 2009 period, 
    ''' even though this person did not take any classes
    ''' </summary>
    Public Sub addStudentToProcess(ByVal ParamArray stud() As Student)

        For Each cstudent As Student In stud

            For Each dtype As DiplomaType In Me.period.DiplomaSuperType.DiplomaTypes

                For Each dreq As DiplomaRequirement In dtype.DiplomaRequirements
                    Dim ssr As IStudentSatisfiedCertReqs = _
                        Me.getStudentSatisfiedCertReqs(cstudent, dreq.Certification)
                    ssr.LoadStudentSatisfiedRequirementsFromPassedPeriods()

                Next
            Next
        Next

    End Sub

    ''' <summary>
    ''' See addStudentToProcess(ByVal ParamArray stud() As Student) above
    ''' </summary>
    ''' <param name="memberNumbers">Integer Array of Member Numbers</param>
    ''' <remarks>used for unit tests only</remarks>
    Public Sub addStudentToProcess(ByVal ParamArray memberNumbers() As Integer)

        For Each cStudentNumber As Integer In memberNumbers
            Dim cstudent As Student = StudentDataUtils.findOne("MemberNumber={0}", cStudentNumber)
            Me.addStudentToProcess(cstudent)
        Next

    End Sub

    Public Function getStudentSatisfiedCertReqs( _
                                ByVal student As Student, _
                                ByVal certType As CertificationType) As IStudentSatisfiedCertReqs _
                            Implements ICreditsAndExamsProcessor.getStudentSatisfiedCertReqs

        Dim ret As IStudentSatisfiedCertReqs
        Dim skey As String = student.StudentId & "," & certType.CertificationTypeId

        'we check: has this student already earn the certificate?
        If (Me.dictStudentSatisfiedCertReqs Is Nothing) Then
            If student.MemberNumber = PeriodProcessor.TRACK_STUDENT_NUMBER Then
                Trace.TraceInformation("Instantiate dictStudentSatisfiedCertReqs {0}", _
                             student.MemberNumber)
            End If
            Me.dictStudentSatisfiedCertReqs = New Dictionary(Of String, IStudentSatisfiedCertReqs)
        End If

        If Me.dictStudentSatisfiedCertReqs.ContainsKey(skey) Then
            ret = dictStudentSatisfiedCertReqs.Item(skey)
        Else
            ret = getStudentSatisfiedCertReqsInstance(student, certType)
            Me.dictStudentSatisfiedCertReqs.Add(skey, ret)
        End If

        Return ret

    End Function

    Private Function getStudentSatisfiedCertReqsInstance(ByVal student As Student, _
                                                        ByVal certType As CertificationType) _
                    As IStudentSatisfiedCertReqs

        If certType.NumberOptionalRequired.GetValueOrDefault = 0 Then
            Return New StudentSatisfiedCertReqs(Me.period, student, certType)
        Else
            Return New StudentSatisfiedOptionalCertReqs(Me.period, student, certType)
        End If

    End Function

    Public Sub processCredits() Implements ICreditsAndExamsProcessor.processCredits

        'first, get all exceptions.  note that we do **not** exclude exceptions 
        'that are already used.  There are cases where credits are used 
        Dim lessonSQL = <sql>
             StudentLessonExceptionId not in (select StudentLessonExceptionId from StudentLessonExceptionUsage) and EffectiveDate&lt;={0}
             and lessonid in (select lessonid from vDiplomaSuperTypeLesson where DiplomaSuperTypeId={1})
                            </sql>
        Dim els As List(Of StudentLessonCredit) = StudentLessonCreditDataUtils.findList(lessonSQL.Value, _
                                                                                        period.PeriodDate.GetValueOrDefault, _
                                                                                        period.DiplomaSuperTypeId.GetValueOrDefault)

        'logger.DebugFormat("Number of Exceptions: {0}", els.Count)

        'loop thru each of the student's unused exceptions
        For Each el As StudentLessonCredit In els

            If el.Student.MemberNumber = PeriodProcessor.TRACK_STUDENT_NUMBER Then

                Trace.TraceInformation("Member Number: {0} Add Credit for : {1}", _
                                 el.Student.MemberNumber, el.Lesson.LessonCode)

            End If

            'change: 2/2/2013 check effective date of exception!
            'perioddate: 1/1/2004, exception Effective date: 1/1/2005 - not applicable
            'perioddate: 1/1/2004, exception Effective date: 1/1/2004 - applicable
            'perioddate: 1/1/2004, exception Effective date: 1/1/2003 - applicable
            If Lesson.isLessonTiedToDiplomaType(el.Lesson, Me.period.DiplomaSuperType) Then

                Dim ls As Lesson = LessonDataUtils.findByKey(el.LessonId.GetValueOrDefault)

                If ls IsNot Nothing Then
                    'loop thru each of the requirements of the lesson
                    For Each cr As CertificationRequirement In ls.CertificationRequirements
                        Dim ssr As IStudentSatisfiedCertReqs = _
                            Me.getStudentSatisfiedCertReqs(el.Student, cr.Certification)

                        Dim sleu As StudentLessonCreditUsage = StudentLessonCreditUsageFactory.Create
                        Dim csr As CertificationSatisfiedRequirement = CertificationSatisfiedRequirementFactory.Create

                        sleu.StudentLessonExceptionId = el.StudentLessonExceptionId
                        csr.CertificationRequirementId = cr.CertificationRequirementId
                        csr.CreditUsage = sleu

                        ssr.addSatifiedRequirement(csr) 'link with satisfied requirement

                    Next
                End If
            End If 'check of effective date
        Next

    End Sub


End Class
